package brainsplash.gyrusscope.game;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import android.view.Display;
import javax.microedition.khronos.opengles.GL10;

import android.content.res.Configuration;
import android.util.Log;
import brainsplash.gyrusscope.framework.Game;
import brainsplash.gyrusscope.framework.Input.KeyEvent;
import brainsplash.gyrusscope.framework.Input.TouchEvent;
import brainsplash.gyrusscope.framework.gl.Camera2D;
import brainsplash.gyrusscope.framework.gl.FPSCounter;
import brainsplash.gyrusscope.framework.gl.SpriteBatcher;
import brainsplash.gyrusscope.framework.impl.GLGame;
import brainsplash.gyrusscope.framework.impl.GLScreen;
import brainsplash.gyrusscope.framework.math.OverlapTester;
import brainsplash.gyrusscope.framework.math.Rectangle;
import brainsplash.gyrusscope.framework.math.Vector2;

public class GameScreen extends GLScreen {
    static final int GAME_READY = 0;
    static final int GAME_RUNNING = 1;
    static final int GAME_PAUSED = 2;
    static final int GAME_LEVEL_END = 3;
    static final int GAME_OVER = 4;
  
    public static int state;
    Camera2D guiCam;
    Vector2 touchPoint;
    SpriteBatcher batcher;
    World world;
    WorldRenderer renderer;
    Rectangle pauseBounds;
    Rectangle resumeBounds;
    Rectangle quitBounds;
    Rectangle leftBounds;
    Rectangle rightBounds;
    Rectangle fireBounds;
    int lastScore;
    String endMessage;
    FPSCounter fpsCounter;
    float offset_x;
    float offset_y;
    float gameOverTimer;
    
    public GameScreen(Game game) {
        super(game);
        state = GAME_READY;
        guiCam = new Camera2D(glGraphics, 320, 480);
        touchPoint = new Vector2();
        batcher = new SpriteBatcher(glGraphics, 1000);

        world = new World();
        renderer = new WorldRenderer(glGraphics, batcher, world);
        pauseBounds = new Rectangle(320 - 64, 480 - 64, 64, 64);
        resumeBounds = new Rectangle(160 - 96, 240, 192, 36);
        quitBounds = new Rectangle(160 - 96, 240 - 36, 192, 36);
        leftBounds = new Rectangle(0, 0, 160, 480);
        rightBounds = new Rectangle(160, 0, 160, 480);
        fireBounds = new Rectangle(106, 0, 108, 108);
        lastScore = 0;
        fpsCounter = new FPSCounter();
    }
    

	@Override
	public void update(float deltaTime) {
	    if(deltaTime > 0.1f)
	        deltaTime = 0.1f;
	    
	    Particles.update(); 
		
	    switch(state) {
	    case GAME_READY:
	        updateReady();
	        break;
	    case GAME_RUNNING:
	        updateRunning(deltaTime);
	        break;
	    case GAME_PAUSED:
	        updatePaused();
	        break;
	    case GAME_LEVEL_END:
	        updateLevelEnd();
	        break;
	    case GAME_OVER:
        	updateGameOver();
	    	gameOverTimer -= deltaTime;
	        break;
	    }
	}
	
	private void updateReady() {
	    if(game.getInput().getTouchEvents().size() > 0) {
	        state = GAME_RUNNING;
	        world.score = 0;
	    }
	}
	
	private void updateRunning(float deltaTime) {
		int rot = Assets.getRotation() * 90;
		float x = -game.getInput().getAccelX() + offset_x;
	    float y = -game.getInput().getAccelY() + offset_y;
	    offset_x = x - offset_x;
	    offset_y = y - offset_y;
	    
	    // If accelerometer values equal 0 then we are probably in the emulator
	    boolean isEmulator = false;
	    if (x==0 && y==0) {isEmulator = true;}
	    
	    //TODO: Fix Keyboard controls
	    /*Configuration config = glGame.getResources().getConfiguration();
	    if (config.keyboardHidden==Configuration.HARDKEYBOARDHIDDEN_NO && !isEmulator) {
	    	List<KeyEvent> keyEvents = game.getInput().getKeyEvents();
	    	for(int i = 0; i < keyEvents.size(); i++) {
	    		KeyEvent event = keyEvents.get(i);
		        if(event.type != android.view.KeyEvent.ACTION_DOWN) 
		            continue;
		        //right: 20 32
		        //left: 19 29
		        if (event.keyCode == 20 || event.keyCode == 32) { //right
		        	world.player.direction += 5 * 25 * deltaTime;
		        } 
		        else if (event.keyCode == 19 || event.keyCode == 29) { //left
		        	world.player.direction -= 5 * 25 * deltaTime;
		        }
		        else {
		        	world.blasts.addAll(world.player.fire(3));
		        }
	    	}
	    }*/
	    if (true) {
		    if (!isEmulator) {
			    float d1 = -90;//world.player.direction;
			    float d2 = (float) (Math.toDegrees(Math.atan2(y, x)) + rot);
			    if (d2-d1 <= -180) {d2 += 360;}
			    else if (d2-d1 >= 180) {d2 -= 360;}		    
			    world.player.direction += Math.max(Math.min((d2-d1), 5), -5) * 30 * deltaTime;
		    };
		    
		    List<TouchEvent> touchEvents = game.getInput().getTouchEvents();
		    for(int i = 0; i < touchEvents.size(); i++) {
		        TouchEvent event = touchEvents.get(i);
		        if(event.type != TouchEvent.TOUCH_UP && !isEmulator)
		            continue;
		        
		        touchPoint.set(event.x, event.y);
		        guiCam.touchToWorld(touchPoint);
		        
		        if(OverlapTester.pointInRectangle(pauseBounds, touchPoint)) {
		            Assets.playSound(Assets.clickSound);
		            state = GAME_PAUSED;
		            return;
		        } 
		        
		        if(OverlapTester.pointInRectangle(fireBounds, touchPoint)) {
		        	if (world.player.reload <= world.player.reloadCounter)
		        	{
			        	world.blasts.addAll(world.player.fire(3));
			        	world.player.reloadCounter = 0;
		        	}
		        } else if(OverlapTester.pointInRectangle(leftBounds, touchPoint)) {
		        	//Log.d(">>>>>>>>>>", "Go Left!!!!!!!!");
		        	if (isEmulator) {
		        		world.player.direction -= 5 * 25 * deltaTime;
		        	} else if (world.player.reload <= world.player.reloadCounter) {
			        	world.blasts.addAll(world.player.fire(3));
			        	world.player.reloadCounter = 0;
		        	}
		        } else if(OverlapTester.pointInRectangle(rightBounds, touchPoint)) {
		        	//Log.d(">>>>>>>>>>", "Go Right!!!!!!!");
		        	if (isEmulator) {
		        		world.player.direction += 5 * 25 * deltaTime;
		        	} else if (world.player.reload <= world.player.reloadCounter) {
			        	world.blasts.addAll(world.player.fire(3));
			        	world.player.reloadCounter = 0;
		        	}
		        	
		        }
		        
		    }
	    }
	    
	    if(world.state == World.WORLD_STATE_GAME_OVER) {
	        state = GAME_OVER;
	        gameOverTimer = 0.6f; 
	        if(world.score >= Settings.highscores[9]) {
	            endMessage = "NEW HIGH SCORE!";
		        Settings.addScore(world.score);
		        Settings.save(game.getFileIO());
	        }
	        else { endMessage = ""; }
	    }
	}
	
	private void updatePaused() {
	    List<TouchEvent> touchEvents = game.getInput().getTouchEvents();
	    int len = touchEvents.size();
	    for(int i = 0; i < len; i++) {
	        TouchEvent event = touchEvents.get(i);
	        if(event.type != TouchEvent.TOUCH_UP)
	            continue;
	        
	        touchPoint.set(event.x, event.y);
	        guiCam.touchToWorld(touchPoint);
	        
	        if(OverlapTester.pointInRectangle(resumeBounds, touchPoint)) {
	            Assets.playSound(Assets.clickSound);
	            state = GAME_RUNNING;
	            return;
	        }
	        
	        if(OverlapTester.pointInRectangle(quitBounds, touchPoint)) {
	            Assets.playSound(Assets.clickSound);
	            game.setScreen(new MainMenuScreen(game));
	            return;
	        }
	    }
	}
	
	private void updateLevelEnd() {
	    List<TouchEvent> touchEvents = game.getInput().getTouchEvents();
	    int len = touchEvents.size();
	    for(int i = 0; i < len; i++) {
	        TouchEvent event = touchEvents.get(i);
	        if(event.type != TouchEvent.TOUCH_UP)
	            continue;
	        state = GAME_READY;
	    }
	}
	
	private void updateGameOver() {
	    List<TouchEvent> touchEvents = game.getInput().getTouchEvents();
    	if (gameOverTimer <= 0) {
		    int len = touchEvents.size();
		    for(int i = 0; i < len; i++) {
		        TouchEvent event = touchEvents.get(i);
		        if(event.type != TouchEvent.TOUCH_UP)
		            continue;
		        game.setScreen(new MainMenuScreen(game));
		        break;
	    	}
	    }
	}

	@Override
	public void present(float deltaTime) {
	    GL10 gl = glGraphics.getGL();
	    gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
	    gl.glEnable(GL10.GL_TEXTURE_2D);
	    
	    renderer.render();
	    
	    guiCam.setViewportAndMatrices();
	    gl.glEnable(GL10.GL_BLEND);
	    gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
	    batcher.beginBatch(Assets.items);
	    switch(state) {
		    case GAME_READY:
		        presentReady();
		        break;
		    case GAME_RUNNING:
		        world.update(deltaTime);
		        presentRunning();
		        break;
		    case GAME_PAUSED:
		        presentPaused();
		        break;
		    case GAME_LEVEL_END:
		        presentLevelEnd();
		        break;
		    case GAME_OVER:
		        presentGameOver();
		        break;
	    }
	    batcher.endBatch();
	    gl.glDisable(GL10.GL_BLEND);
	    fpsCounter.logFrame();
	}
	
	private void presentReady() {
	    batcher.drawSprite(160, 240, 192, 32, Assets.ready);
	}
	
	private void presentRunning() {
	    batcher.drawSprite(320 - 32, 480 - 32, 64, 64, Assets.pause);
	    Assets.font.drawText(batcher, "Score: " + world.score, 16, 480-20);
	    Assets.font.drawText(batcher, "Sheilds: " + world.player.health + "%", 16, 460-20);
	    Assets.font.drawText(batcher, "Wave: " + (Level.waveCounter + 1), 16, 20);

	    /*//Input Debugging Code
	    float x = -game.getInput().getAccelX();
	    float y = -game.getInput().getAccelY();
	    float a = (float) Math.toDegrees(Math.atan2(y, x));
	    float d2 = a;
	    float d1 = world.player.direction;
	    if (d2-d1 <= -180) {d2 += 360;}
	    else if (d2-d1 >= 180) {d2 -= 360;}
	    
	    Assets.font.drawText(batcher, "delta: " + (d2-d1), 16, 100);
	    Assets.font.drawText(batcher, "angle: " + a, 16, 80);
	    Assets.font.drawText(batcher, "x-axis: " + x, 16, 60);
	    Assets.font.drawText(batcher, "y-axis: " + y, 16, 40);
	    Assets.font.drawText(batcher, "z-axis: " + game.getInput().getAccelZ(), 16, 20);
	    Assets.font.drawText(batcher, "Rotation: " + (Assets.getRotation() * 90), 16, 40);
	    */
	}
	
	private void presentPaused() {        
	    batcher.drawSprite(160, 240, 192, 96, Assets.pauseMenu);
	    Assets.font.drawText(batcher, "Score: " + world.score, 16, 480-20);
	    Assets.font.drawText(batcher, "Sheilds: " + world.player.health + "%", 16, 460-20);
	}
	
	private void presentLevelEnd() {
	    String topText = "Level Complete";
	    float topWidth = Assets.font.glyphWidth * topText.length();
	    Assets.font.drawText(batcher, topText, 160 - topWidth / 2, 480 - 40);
	}
	
	private void presentGameOver() {
	    batcher.drawSprite(160, 240, 160, 96, Assets.gameOver);
	    Assets.font.drawText(batcher, endMessage, 16, 480-40);
	    Assets.font.drawText(batcher, "Score: " + world.score, 16, 480-20);
	}

    @Override
    public void pause() {
        if(state == GAME_RUNNING)
            state = GAME_PAUSED;
    }

    @Override
    public void resume() {
    	if(state == GAME_PAUSED) {
    		state = GAME_RUNNING;
    	}
    }

    @Override
    public void dispose() {
    }
}
